/////////////////////////////////////////////////////////////////////////
// 语法分析
// 包括了AST的数据结构和递归下降的语法解析程序

/**
 * 基类，标识AST的一个节点
 */
abstract class AstNode{
    //打印对象信息，prefix是前面填充的字符串，通常用于缩进显示
    public abstract dump(prefix:string):void;
}

/**
 * 语句节点
 * 其子类包括函数声明和函数调用
 */
export abstract class Statement extends AstNode{
    static isStatementNode(node: any): node is Statement {
        if (!node) {
            return false;
        }
        if (Object.getPrototypeOf(node) == Statement.prototype) {
            return true;
        }
        else {
            return false;
        }
    }
}

/**
 * 程序节点，也是AST的根节点
 */
export class Prog extends AstNode{
    stmts: Statement[]; //程序中可以包含多个语句
    constructor(stmts:Statement[]){
        super();
        this.stmts = stmts;
    }
    public dump(prefix:string):void{
        console.log(prefix+"Prog");
        this.stmts.forEach(x => x.dump(prefix+"\t"));
    }
}

/**
 * 函数声明节点
 */
export class FunctionDecl extends Statement{
    name:string;       //函数名称
    body:FunctionBody; //函数体
    constructor(name:string, body:FunctionBody){
        super();
        this.name = name;
        this.body = body;
    }
    public dump(prefix:string):void{
        console.log(prefix+"FunctionDecl "+this.name);
        this.body.dump(prefix+"\t");
    }
}

/**
 * 函数体节点
 */
export class FunctionBody extends AstNode{
    stmts: FunctionCall[];
    constructor(stmts: FunctionCall[]){
        super();
        this.stmts = stmts;
    }
    static isFunctionBodyNode(node: any): node is FunctionBody {
        if (!node) {
            return false;
        }
        if (Object.getPrototypeOf(node) == FunctionBody.prototype) {
            return true;
        }
        else {
            return false;
        }
    }
    public dump(prefix:string):void{
        console.log(prefix+"FunctionBody");
        this.stmts.forEach(x => x.dump(prefix+"\t"));
    }
}

/**
 * 函数调用节点
 */
export class FunctionCall extends Statement{
    name:string;
    parameters: string[];
    definition: FunctionDecl|null = null;  //指向函数的声明
    constructor(name:string, parameters: string[]){
        super();
        this.name = name;
        this.parameters = parameters;
    }
    static isFunctionCallNode(node: any): node is FunctionCall {
        if (!node) {
            return false;
        }
        if (Object.getPrototypeOf(node) == FunctionCall.prototype) {
            return true;
        }
        else {
            return false;
        }
    }
    public dump(prefix:string):void{
        console.log(prefix+"FunctionCall "+this.name + (this.definition!=null ? ", resolved" : ", not resolved"));
        this.parameters.forEach(x => console.log(prefix+"\t"+"Parameter: "+ x));
    }
}

/**
 * 对AST做遍历的Vistor。
 * 这是一个基类，定义了缺省的遍历方式。子类可以覆盖某些方法，修改遍历方式。
 */
export abstract class AstVisitor{
    visitProg(prog:Prog):any{
        let retVal:any;
        for(let x of prog.stmts){
            //根据stmt的类型，进行不同的处理
            if (typeof (x as FunctionDecl).body === 'object'){
                retVal = this.visitFunctionDecl(x as FunctionDecl);
            }
            else{
                retVal = this.visitFunctionCall(x as FunctionCall);
            }
        }
        return retVal;
    }

    //通过函数声明，访问函数体
    //这里要看子类如何继承
    visitFunctionDecl(functionDecl:FunctionDecl):any{
        return this.visitFunctionBody(functionDecl.body);
    }

    //函数体中，依次执行每个函数调用
    visitFunctionBody(functionBody:FunctionBody):any{
        let retVal:any;

        //依次执行函数体中的每个函数调用
        for(let x of functionBody.stmts){
            retVal = this.visitFunctionCall(x);
        }
        return retVal;
    }

    //执行1次函数调用
    //这里要看子类如何继承
    visitFunctionCall(functionCall:FunctionCall):any{return undefined;}
}
